package com.bkgy.controller.technology.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bkgy.controller.planking.entity.TPdoDataL3Cgl1870;
import com.bkgy.controller.planking.entity.TbPlank1870;
import com.bkgy.controller.planking.service.IPdoL3Cgl1870Service;
import com.bkgy.controller.planking.service.ITbPlank1870Service;
import com.bkgy.controller.technology.entity.Cgl1870ProcessDatas;
import com.bkgy.controller.technology.entity.TDefectData;
import com.bkgy.controller.technology.entity.TTechParam;
import com.bkgy.controller.technology.entity.dto.RollInfo;
import com.bkgy.controller.technology.entity.dto.TechChartDtoReq;
import com.bkgy.controller.technology.entity.dto.TechListDtoRes;
import com.bkgy.controller.technology.mapper.ICgl1870ProcessMapper;
import com.bkgy.controller.technology.service.ICgl1870ProcessService;
import com.bkgy.controller.technology.service.ITDefectDataService;
import com.bkgy.controller.technology.service.ITechParamService;
import com.bkgy.modular.datacollect_bx.bean.JDataSavemong1870;
import com.bkgy.sys.common.constant.CommonConstant;
import com.bkgy.sys.common.entity.ResultData;
import com.bkgy.util.DateUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

@Slf4j
@Service
@RequiredArgsConstructor
public class Cgl1870ProcessServiceImpl extends ServiceImpl<ICgl1870ProcessMapper, Cgl1870ProcessDatas>
        implements ICgl1870ProcessService {
    private final IPdoL3Cgl1870Service pdoL31870Service;
    private final ITechParamService checkService;
    private final ITbPlank1870Service plank1870Service;
    private final ITDefectDataService defectService;
    private final MongoTemplate mongoTemplate;

    @Override
    public ResultData<String> transData(String beginTime) {
        //加载PDO_L3中的数据
        List<TPdoDataL3Cgl1870> list = pdoL31870Service.selectCgl1870Data(beginTime);

        List<Cgl1870ProcessDatas> cglList = new ArrayList<>();

        //指标范围分类存放
        Map<String, List<TTechParam>> paramMap = loadTechParam();

        for (TPdoDataL3Cgl1870 item : list) {
            Cgl1870ProcessDatas obj = new Cgl1870ProcessDatas();
            obj.setEntid(item.getEntid());
            obj.setExtid(item.getExtid());
            obj.setStartime(item.getProdStartTime());
            obj.setEndtime(item.getProdEndTime());
            obj.setToc(DateUtil.getDateToString(item.getCreateTime(), "yyyyMMddHHmmss"));
            obj.setSteelgrade(item.getSteelgrade());
            obj.setInMatWidth(item.getInMat1Width());
            obj.setInMatThk(item.getInMat1Thick());
            String code = item.getSurfaceAccuClassCode();
            obj.setSurfaceAccuClassCode(BigDecimal.valueOf(Integer.parseInt(code)));
            obj.setZncoatKind(item.getZncoatKind());
            obj.setOilamount(item.getOilamount());

            buildCheckResult(paramMap, obj);

            cglList.add(obj);
        }

        saveBatch(cglList);
        return ResultData.ResultDataSuccess("success");
    }

    @Override
    public void compensateCheck() {
        Map<String, List<TTechParam>> paramMap = loadTechParam();
        LambdaQueryWrapper<Cgl1870ProcessDatas> w1 = new LambdaQueryWrapper<>();
        w1.isNull(Cgl1870ProcessDatas::getSprayCondActAvg);
        String levelTime = DateUtil.getDateToString(DateUtil.getBeforeHour(), "yyyyMMddHHmmss");
        w1.gt(Cgl1870ProcessDatas::getEndtime, levelTime);
        List<Cgl1870ProcessDatas> dataList = list(w1);
        for (Cgl1870ProcessDatas obj : dataList) {
            buildCheckResult(paramMap, obj);
        }
        updateBatchById(dataList);
    }

    private Map<String, List<TTechParam>> loadTechParam() {
        //指标范围分类存放
        Map<String, List<TTechParam>> paramMap = new HashMap<>();
        List<TTechParam> paramList = checkService.list();
        for (TTechParam p : paramList) {
            String key = StringUtils.isEmpty(p.getBrand()) ? p.getProNo() : p.getBrand();
            if (paramMap.containsKey(key)) {
                paramMap.get(key).add(p);
            } else {
                List<TTechParam> pList = new ArrayList<>();
                pList.add(p);
                paramMap.put(key, pList);
            }
        }
        return paramMap;
    }

    private void buildCheckResult(Map<String, List<TTechParam>> paramMap, Cgl1870ProcessDatas obj) {
        String[] arr = new String[]{
                "cgl_alkali_spray_cond_act_avg", "cgl_alkali_brush_cond_act_avg", "cgl_clean_alkali_spray_temp_avg",
                "cgl_clean_alkali_brush_temp_avg", "cgl_clean_elec_temp_avg", "cgl_clean_rinse_temp_avg",
                "cgl_elec_cond_act_avg", "cgl_rinse_cond_act_avg", "cgl_spm_liquid_conc_avg",
                "cgl_air_knife_dis_top_avg", "cgl_air_knife_dis_btm_avg", "cgl_air_knife_high_top_avg",
                "cgl_air_knife_high_btm_avg", "cgl_gi_znpot_temp_avg", "cgl_ga_znpot_temp_avg",
                "cgl_spm_elong_act_avg", "cgl_oil_amount_strip_avg", "cgl_p5_temp_act_avg",
                "cgl_scs_strip_temp_act_avg", "cgl_rcs_strip_temp_act_avg", "cgl_p10_temp_act_avg"
        };

        //从MongoDB中读取轧卷对应的指标
        Query query = new Query();
        query.addCriteria(Criteria.where("flag").is(1));
        for (int i = 0; i < arr.length; i++) {
            query.fields().include("trailValues." + arr[i]);
        }
        query.addCriteria(Criteria.where("extid").is(obj.getExtid()));

        JDataSavemong1870 mongoData = mongoTemplate.findOne(query, JDataSavemong1870.class);
        if (mongoData != null) {
            Map<String, Double> map = mongoData.getTrailValues();
            obj.setSprayCondActAvg(readValue(map, arr[0]));
            obj.setBrushCondActAvg(readValue(map, arr[1]));
            obj.setSprayTempAvg(readValue(map, arr[2]));
            obj.setBrushTempAvg(readValue(map, arr[3]));
            obj.setElecTempAvg(readValue(map, arr[4]));
            obj.setRinseTempAvg(readValue(map, arr[5]));
            obj.setElecCondActAvg(readValue(map, arr[6]));
            obj.setRinseCondActAvg(readValue(map, arr[7]));
            obj.setSpmLiquidConcAvg(readValue(map, arr[8]));
            obj.setAirKnifeDisTopAvg(readValue(map, arr[9]));
            obj.setAirKnifeDisBtmAvg(readValue(map, arr[10]));
            obj.setAirKnifeHighTopAvg(readValue(map, arr[11]));
            obj.setAirKnifeHighBtmAvg(readValue(map, arr[12]));
            obj.setGiZnpotTempAvg(readValue(map, arr[13]));
            obj.setGaZnpotTempAvg(readValue(map, arr[14]));
            obj.setSpmElongActAvg(readValue(map, arr[15]));
            obj.setOilAmountStripAvg(readValue(map, arr[16]));
            obj.setP5TempActAvg(readValue(map, arr[17]));
            obj.setScsStripTempActAvg(readValue(map, arr[18]));
            obj.setRcsStripTempActAvg(readValue(map, arr[19]));
            obj.setP9TempActAvg(readValue(map, arr[20]));
        } else {
            log.warn("从MongoDB中未取到入口卷号 {} 的数据", obj.getExtid());
            return;
        }

        checkService.checkParam(paramMap, obj);
    }

    @Override
    public List<TechListDtoRes> load1870ProcessData(TechChartDtoReq tc) {
        List<TechListDtoRes> list = new ArrayList<>();

        LambdaQueryWrapper<Cgl1870ProcessDatas> w = build1870Wrapper(tc);
        //查询出口卷号
        w.select(Cgl1870ProcessDatas::getExtid);
        List<Cgl1870ProcessDatas> dbList = list(w);
        for (int i = 0; i < dbList.size(); i++) {
            Cgl1870ProcessDatas obj = dbList.get(i);
            TechListDtoRes res = new TechListDtoRes();
            res.setSeqno(i + 1);
            res.setVolumeNo(obj.getExtid());
            list.add(res);
        }
        return list;
    }

    @Override
    public LambdaQueryWrapper<Cgl1870ProcessDatas> build1870Wrapper(TechChartDtoReq tc) {
        Date d1 = DateUtil.getStringToDate("yyyy-MM-dd HH:mm:ss", tc.getStartDate());
        Date d2 = DateUtil.getStringToDate("yyyy-MM-dd HH:mm:ss", tc.getEndDate());
        LambdaQueryWrapper<Cgl1870ProcessDatas> w = new LambdaQueryWrapper<>();
        //开始时间
        if (StringUtils.isNotEmpty(tc.getStartDate())) {
            w.ge(Cgl1870ProcessDatas::getEndtime, DateUtil.getDateToString(d1, "yyyyMMddHHmmss"));
        } else {
            //最近1天
            Calendar cal = Calendar.getInstance();
            cal.setTime(d1);
            cal.add(Calendar.DAY_OF_MONTH, -1);
            w.ge(Cgl1870ProcessDatas::getEndtime, DateUtil.getDateToString(cal.getTime(), "yyyyMMddHHmmss"));
        }
        //结束时间
        if (StringUtils.isNotEmpty(tc.getEndDate())) {
            w.le(Cgl1870ProcessDatas::getEndtime, DateUtil.getDateToString(d2, "yyyyMMddHHmmss"));
        }
        //钢种
        if (StringUtils.isNotEmpty(tc.getSteelGrade())) {
            w.eq(Cgl1870ProcessDatas::getSteelgrade, tc.getSteelGrade());
        }
        //入口宽度
        if (tc.getEntWidthStart() != null) {
            w.ge(Cgl1870ProcessDatas::getInMatWidth, tc.getEntWidthStart());
        }
        if (tc.getEntWidthEnd() != null) {
            w.le(Cgl1870ProcessDatas::getInMatWidth, tc.getEntWidthEnd());
        }
        //入口厚度
        if (tc.getEntThickStart() != null) {
            w.ge(Cgl1870ProcessDatas::getInMatThk, tc.getEntThickStart());
        }
        if (tc.getEntThickEnd() != null) {
            w.le(Cgl1870ProcessDatas::getInMatThk, tc.getEntThickEnd());
        }
        w.orderByAsc(Cgl1870ProcessDatas::getEndtime);
        return w;
    }

    @Override
    public ResultData<String> rollInfo(TechChartDtoReq tc) {
        Date d = new Date();
        String d1 = DateUtil.getBeforeHourStart(d);
        String d2 = DateUtil.getDateToString(d, "yyyyMMddHH");
        Calendar cal = Calendar.getInstance();
        cal.setTime(d);
        int h = cal.get(Calendar.HOUR_OF_DAY);

        LambdaQueryWrapper<Cgl1870ProcessDatas> wrapper = new LambdaQueryWrapper();
        wrapper.select(Cgl1870ProcessDatas::getSprayCondActJudge,
                Cgl1870ProcessDatas::getBrushCondActJudge,
                Cgl1870ProcessDatas::getSprayTempJudge,
                Cgl1870ProcessDatas::getBrushTempJudge,
                Cgl1870ProcessDatas::getElecTempJudge,
                Cgl1870ProcessDatas::getRinseTempJudge,
                Cgl1870ProcessDatas::getElecCondActJudge,
                Cgl1870ProcessDatas::getRinseCondActJudge,
                Cgl1870ProcessDatas::getSpmLiquidConcJudge,
                Cgl1870ProcessDatas::getAirKnifeDisTopJudge,
                Cgl1870ProcessDatas::getAirKnifeDisBtmJudge,
                Cgl1870ProcessDatas::getAirKnifeHighTopJudge,
                Cgl1870ProcessDatas::getAirKnifeHighBtmJudge,
                Cgl1870ProcessDatas::getGiZnpotTempJudge,
                Cgl1870ProcessDatas::getSpmElongActJudge,
                Cgl1870ProcessDatas::getOilAmountStripJudge,
                Cgl1870ProcessDatas::getP6TempActJudge,
                Cgl1870ProcessDatas::getRcsStripTempActJudge,
                Cgl1870ProcessDatas::getP9TempActJudge
        ).ge(Cgl1870ProcessDatas::getEndtime, d1).le(Cgl1870ProcessDatas::getEndtime, d2);
        List<Cgl1870ProcessDatas> dbList = list(wrapper);
        String[] titleArr = new String[]{
                "碱喷电导率实际", "碱刷电导率实际", "清洗段碱喷循环槽温度", "清洗段碱刷循环槽温度", "清洗段电解循环槽温度",
                "清洗段漂洗循环槽温度", "电解电导率实际", "漂洗电导率实际", "光整液浓度", "气刀距离（上表面）平均值",
                "气刀距离（下表面）平均值", "气刀高度（上表面）平均值", "气刀高度（下表面）平均值", "GI锌锅温度", "延伸率实际",
                "涂油重量", "加热温度", "快冷温度", "入锌锅温度"};
        int[] countArr = new int[titleArr.length];
        for (Cgl1870ProcessDatas data : dbList) {
            if (data.getSprayCondActJudge() != null && data.getSprayCondActJudge() == 1) countArr[0]++;
            if (data.getBrushCondActJudge() != null && data.getBrushCondActJudge() == 1) countArr[1]++;
            if (data.getSprayTempJudge() != null && data.getSprayTempJudge() == 1) countArr[2]++;
            if (data.getBrushTempJudge() != null && data.getBrushTempJudge() == 1) countArr[3]++;
            if (data.getElecTempJudge() != null && data.getElecTempJudge() == 1) countArr[4]++;

            if (data.getRinseTempJudge() != null && data.getRinseTempJudge() == 1) countArr[5]++;
            if (data.getElecCondActJudge() != null && data.getElecCondActJudge() == 1) countArr[6]++;
            if (data.getRinseCondActJudge() != null && data.getRinseCondActJudge() == 1) countArr[7]++;
            if (data.getSpmLiquidConcJudge() != null && data.getSpmLiquidConcJudge() == 1) countArr[8]++;
            if (data.getAirKnifeDisTopJudge() != null && data.getAirKnifeDisTopJudge() == 1) countArr[9]++;

            if (data.getAirKnifeDisBtmJudge() != null && data.getAirKnifeDisBtmJudge() == 1) countArr[10]++;
            if (data.getAirKnifeHighTopJudge() != null && data.getAirKnifeHighTopJudge() == 1) countArr[11]++;
            if (data.getAirKnifeHighBtmJudge() != null && data.getAirKnifeHighBtmJudge() == 1) countArr[12]++;
            if (data.getGiZnpotTempJudge() != null && data.getGiZnpotTempJudge() == 1) countArr[13]++;
            if (data.getSpmElongActJudge() != null && data.getSpmElongActJudge() == 1) countArr[14]++;

            if (data.getOilAmountStripJudge() != null && data.getOilAmountStripJudge() == 1) countArr[15]++;
            if (data.getP6TempActJudge() != null && data.getP6TempActJudge() == 1) countArr[16]++;
            if (data.getRcsStripTempActJudge() != null && data.getRcsStripTempActJudge() == 1) countArr[17]++;
            if (data.getP9TempActJudge() != null && data.getP9TempActJudge() == 1) countArr[18]++;
        }
        List<RollInfo> list = new ArrayList<>();
        for (int i = 0; i < titleArr.length; i++) {
            list.add(new RollInfo(titleArr[i], countArr[i]));
        }
        Collections.sort(list);

        String res = "";
        StringBuffer sbf = new StringBuffer();
        sbf.append(h - 1).append(":00-").append(h).append(":00").append(" 总生产卷数:" + dbList.size());
        sbf.append(list.size() == 0 ? "。" : "，");
        for (int i = 0; i < list.size(); i++) {
            RollInfo ri = list.get(i);
            if (ri.getCount() == 0) {
                res = sbf.substring(0, sbf.length() - 1) + "。";
                break;
            }
            sbf.append(ri.getTitle()).append("超限:").append(ri.getCount());
            sbf.append(i < list.size() - 1 ? "，" : "。");
        }
        return ResultData.ResultDataSuccess(res.length() > 0 ? res : sbf.toString());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean splitPlankService() {
        String beginTime = "20250901";//库表为空时，从9月1日开始刷入数据

        //删掉最新出口卷所对应的入口卷分出来的所有出口卷
        TbPlank1870 p = plank1870Service.selectTopRecord();
        if (p != null) {
            String entid = p.getEntid();
            LambdaQueryWrapper<TbPlank1870> w = new LambdaQueryWrapper();
            w.select(TbPlank1870::getProdEndTime).eq(TbPlank1870::getEntid, entid).orderByAsc(TbPlank1870::getProdEndTime);
            List<TbPlank1870> list = plank1870Service.list(w);
            beginTime = list.get(0).getProdEndTime();

            //删掉时间点以后的数据
            LambdaQueryWrapper<TbPlank1870> w1 = new LambdaQueryWrapper();
            w1.ge(TbPlank1870::getProdEndTime, beginTime);
            plank1870Service.remove(w1);
        }

        //查询生产表中的大于此时间点的外板生产数据
        List<String> extIdList = new ArrayList<>();
        List<TbPlank1870> list = plank1870Service.selectPdoData(beginTime);
        String lastEntId = null;//上一卷的入口卷号
        for (int i = 0; i < list.size(); i++) {
            TbPlank1870 plank = list.get(i);

            //入口卷号不同，分卷结束
            if (i > 0 && !plank.getEntid().equals(lastEntId)) {
                //更新上一个完整入口卷的各个分卷投入重量
                boolean flag = true;//是否是同一个入口卷
                for (int j = i - 1; j > 0 && flag; j--) {
                    TbPlank1870 currentObj = list.get(j);
                    TbPlank1870 lastObj = list.get(j - 1);
                    if (currentObj.getEntid().equals(lastObj.getEntid())) {
                        //处于同一个入口卷号内，从最后一个分卷按比例推算上一个分卷的投入量。当前卷投入:当前卷产出=上一卷投入:上一卷产出
                        BigDecimal touru = currentObj.getInMat1UseWt().multiply(lastObj.getOutMatWt()).divide(currentObj.getOutMatWt(), 4, BigDecimal.ROUND_HALF_UP);
                        lastObj.setInMat1UseWt(touru);
                    } else flag = false;
                }
            }
            lastEntId = plank.getEntid();
            extIdList.add(plank.getExtid());
        }
        //根据出口卷号查询缺陷表
        LambdaQueryWrapper<TDefectData> w = new LambdaQueryWrapper();
        Map<String, TDefectData> defectMap = new HashMap<>();
        w.in(TDefectData::getExtId, extIdList).orderByAsc(TDefectData::getDefectVersionTime1);
        List<TDefectData> defectList = defectService.list(w);
        for (TDefectData defectData : defectList) {
            defectMap.put(defectData.getExtId(), defectData);
        }

        for (TbPlank1870 plank : list) {
            if (defectMap.containsKey(plank.getExtid())) {
                TDefectData defect = defectMap.get(plank.getExtid());
                plank.setDefectCode1(defect.getDefectCode1());
                plank.setDefectComment1(defect.getDefectComment1());
                String attrCode = defect.getDefectAttributionCode1();
                plank.setDefectAttributionCode1(attrCode);
                plank.setDefectAttributionComment(CommonConstant.tPdi1870HomeMap.get(attrCode));
            }
        }

        //分析存表
        plank1870Service.saveBatch(list);
        return true;
    }

    @Override
    public void updatePlankDefectInfo() {
        LambdaQueryWrapper<TbPlank1870> wrapper = new LambdaQueryWrapper<>();
        wrapper.isNull(TbPlank1870::getDefectCode1);
        //更新1天内记录的缺陷信息
        String levelTime = DateUtil.getDateToString(DateUtil.getBeforDate(), "yyyyMMddHHmmss");
        wrapper.gt(TbPlank1870::getProdEndTime, levelTime);
        List<TbPlank1870> list = plank1870Service.list(wrapper);
        if (list.size() == 0)
            return;
        List<String> extIdList = new ArrayList<>();
        for (TbPlank1870 plank : list) {
            extIdList.add(plank.getExtid());
        }

        LambdaQueryWrapper<TDefectData> w = new LambdaQueryWrapper<>();
        w.in(TDefectData::getExtId, extIdList);
        Map<String, TDefectData> defectMap = new HashMap<>();
        List<TDefectData> defectList = defectService.list(w);
        for (TDefectData defectData : defectList) {
            defectMap.put(defectData.getExtId(), defectData);
        }
        for (TbPlank1870 plank : list) {
            if (defectMap.containsKey(plank.getExtid())) {
                TDefectData defect = defectMap.get(plank.getExtid());
                plank.setDefectCode1(defect.getDefectCode1());
                plank.setDefectComment1(defect.getDefectComment1());
                String attrCode = defect.getDefectAttributionCode1();
                plank.setDefectAttributionCode1(attrCode);
                plank.setDefectAttributionComment(CommonConstant.tPdi1870HomeMap.get(attrCode));
            }
        }
        plank1870Service.updateBatchById(list);
    }

    private BigDecimal readValue(Map<String, Double> map, String key) {
        if (map.get(key) != null) {
            return BigDecimal.valueOf(map.get(key));
        }
        log.warn("{} 变量数据不存在", key);
        return null;
    }
}
